/*
 *
 * @APPLE_LICENSE_HEADER_START@
 *
 * Copyright (c) 1999-2008 Apple Inc.  All Rights Reserved.
 *
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this
 * file.
 *
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 *
 * @APPLE_LICENSE_HEADER_END@
 *
 */
 /*
	 File:       OSCond.cpp

	 Contains:   Implementation of OSCond class



 */

#include "OSCond.h"
#include "OSMutex.h"
#include "OSThread.h"
#include "MyAssert.h"

#if __PTHREADS_MUTEXES__
#include <sys/time.h>
#endif


OSCond::OSCond()
{
#ifdef __Win32__
	fCondition = ::CreateEvent(NULL, FALSE, FALSE, NULL);
	Assert(fCondition != NULL);
#elif __PTHREADS_MUTEXES__
#if __MacOSX__
	int ret = pthread_cond_init(&fCondition, NULL);
	Assert(ret == 0);
#else
	pthread_condattr_t cond_attr;
	pthread_condattr_init(&cond_attr);
	int ret = pthread_cond_init(&fCondition, &cond_attr);
	Assert(ret == 0);
#endif
#else
	fCondition = mycondition_alloc();
	Assert(fCondition != NULL);
#endif
}

OSCond::~OSCond()
{
#ifdef __Win32__
	BOOL theErr = ::CloseHandle(fCondition);
	Assert(theErr == TRUE);
#elif __PTHREADS_MUTEXES__
	pthread_cond_destroy(&fCondition);
#else
	Assert(fCondition != NULL);
	mycondition_free(fCondition);
#endif
}

#if __PTHREADS_MUTEXES__
void OSCond::TimedWait(OSMutex* inMutex, SInt32 inTimeoutInMilSecs)
{
	struct timespec ts;
	struct timeval tv;
	struct timezone tz;
	int sec, usec;

	//These platforms do refcounting manually, and wait will release the mutex,
	// so we need to update the counts here

	inMutex->fHolderCount--;
	inMutex->fHolder = 0;


	if (inTimeoutInMilSecs == 0)
		(void)pthread_cond_wait(&fCondition, &inMutex->fMutex);
	else
	{
		gettimeofday(&tv, &tz);
		sec = inTimeoutInMilSecs / 1000;
		inTimeoutInMilSecs = inTimeoutInMilSecs - (sec * 1000);
		Assert(inTimeoutInMilSecs < 1000);
		usec = inTimeoutInMilSecs * 1000;
		Assert(tv.tv_usec < 1000000);
		ts.tv_sec = tv.tv_sec + sec;
		ts.tv_nsec = (tv.tv_usec + usec) * 1000;
		Assert(ts.tv_nsec < 2000000000);
		if (ts.tv_nsec > 999999999)
		{
			ts.tv_sec++;
			ts.tv_nsec -= 1000000000;
		}
		(void)pthread_cond_timedwait(&fCondition, &inMutex->fMutex, &ts);
	}


	inMutex->fHolderCount++;
	inMutex->fHolder = pthread_self();

}
#endif
